<template>
  <el-tree
    ref="deptTree"
    :data="units"
    :default-expand-all="true"
    :highlight-current="true"
    :props="defaultProps"
    :expand-on-click-node="false"
    :style="$attrs.style"
    :show-checkbox="props.isMultiple"
    :current-node-key="chioseKey"
    :default-checked-keys="checkboxKey"
    :check-strictly="props.checkstrictly"
    node-key="Id"
    @node-click="chioseUnit"
    @check-change="checkChange"
  >
    <template #default="{ node, data }">
      <div class="slot-t-node">
        <Icon
          v-if="data.style && data.style.icon"
          :icon="data.style.icon"
          :color="data.style.color"
          :style="{ marginRight: '5px' }"
        />
        <span>{{ node.label }}</span>
      </div>
    </template>
  </el-tree>
</template>

<script setup lang="ts">
import { getTree } from '@/api/unit/unit'
import { GetName } from '@/api/base/company'
import { ref, watch } from 'vue'
import { useAppStore } from '@/store/modules/app'
import { propTypes } from '@/utils/propTypes'
import { useUserStoreWithOut } from '@/store/modules/user'

const checkboxKey = ref<string[]>([])
const userStore = useUserStoreWithOut()
const appStore = useAppStore()
const deptDic = {}
const comNameCache = {}
const units = ref([])
const deptTree = ref(null)
const chioseKey = ref<string | number | undefined>(undefined)
const emit = defineEmits(['change', 'load', 'update:modelValue'])
const defaultProps = {
  key: 'Id',
  label: 'Name',
  children: 'Children'
}
let curComId = null
const props = defineProps({
  isUnit: propTypes.bool.def(false),
  checkstrictly: propTypes.bool.def(false),
  unitId: propTypes.arrayOf(propTypes.string),
  deptId: propTypes.arrayOf(propTypes.string),
  status: propTypes.arrayOf(propTypes.number).def([1]),
  companyId: propTypes.string,
  isSubCompany: propTypes.bool.def(false),
  isMultiple: propTypes.bool.def(false),
  isAutoChiose: propTypes.bool.def(false),
  isChoiceDept: propTypes.bool.def(false),
  modelValue: propTypes.arrayOf(propTypes.string),
  isFill: propTypes.bool.def(true),
  styleSet: propTypes.object.def({
    width: '100%'
  })
})
const getDefValue = (str, def) => {
  if (str == null || str === '') {
    return def
  }
  return str
}
const getComName = async (comId) => {
  if (comNameCache[comId] != null) {
    return comNameCache[comId]
  }
  const name = userStore.getComName(comId)
  if (name) {
    return name
  } else {
    return await GetName(comId)
  }
}
const refresh = async () => {
  const res = await load(curComId)
  units.value = res
}
const loadDef = async (comId) => {
  const comName = await getComName(comId)
  comNameCache[comId] = comName
  return [
    {
      Id: 'root',
      Name: comName,
      type: 'com',
      disabled: props.isMultiple,
      comId: comId,
      style: {
        icon: 'ep:flag',
        color: '#409eff'
      },
      Children: null
    }
  ]
}
const initTree = (res) => {
  comNameCache[res.Id] = res.Name
  const data = {
    Id: 'root',
    Name: res.Name,
    type: 'com',
    disabled: props.isMultiple,
    CompanyId: res.Id,
    style: {
      icon: 'ep:flag',
      color: '#409eff'
    },
    Children: null
  }
  initChildren(data, res)
  return [data]
}
const format = (data) => {
  data.disabled = data.IsFill
  if (data.IsUnit) {
    data.type = 'unit'
    data.style = {
      icon: 'ep:list',
      color: '#409eff'
    }
  } else {
    data.type = 'dept'
    data.style = {
      icon: 'svg-icon:peoples',
      color: appStore.getIsDark ? '#fff' : '#000'
    }
  }
  if (data.Children && data.Children.length > 0) {
    data.Children.forEach((c) => {
      c.CompanyId = data.CompanyId
      deptDic[c.Id] = c
      format(c)
    })
  }
}
const initChildren = (data, res) => {
  if (isNull(res.Children) && isNull(res.Dept)) {
    return
  }
  const list = []
  if (!isNull(res.Dept)) {
    res.Dept.forEach((c) => {
      c.CompanyId = res.Id
      deptDic[c.Id] = c
      format(c)
      list.push(c)
    })
  }
  if (!isNull(res.Children)) {
    res.Children.forEach((c) => {
      comNameCache[c.Id] = c.Name
      const data = {
        Id: 'com_' + c.Id,
        Name: c.Name,
        disabled: props.isMultiple,
        type: 'com',
        CompanyId: c.Id,
        style: {
          icon: 'ep:flag',
          color: '#409eff'
        },
        Children: null
      }
      initChildren(data, c)
      list.push(data)
    })
  }
  data.Children = list
}
const isNull = (array) => {
  return array == null || array.length === 0
}
const load = async (comId) => {
  const res = await getTree({
    CompanyId: comId,
    Status: props.status,
    ParentId: props.unitId,
    IsUnit: props.isUnit,
    DeptId: props.deptId,
    IsSubCompany: props.isSubCompany,
    IsFill: props.isFill
  })
  if (res == null) {
    return await loadDef(comId)
  }
  return initTree(res)
}
const findDept = (list) => {
  for (let i = 0; i < list.length; i++) {
    const t = list[i]
    if (t.type !== 'com') {
      return t
    } else if (t.Children != null) {
      const res = findDept(t.Children)
      if (res != null) {
        return res
      }
    }
  }
  return null
}
const loadTree = async () => {
  curComId = getDefValue(props.companyId, userStore.comId)
  const res = await load(curComId)
  units.value = res
  const e = {
    isMultiple: props.isMultiple,
    companyId: curComId,
    comName: comNameCache,
    keys: [],
    value: []
  }
  if (props.isAutoChiose && res.length > 0) {
    const chiose = findDept(res)
    chioseKey.value = chiose.Id
    e.value.push(chiose)
    e.keys.push(chiose.Id)
  } else {
    chioseKey.value = 'root'
  }
  emit('load', e.keys, e)
}
const autoChiose = (data) => {
  if (data.Children && data.Children.length !== 0) {
    let isSet = false
    data.Children.forEach((c) => {
      if (c.type === 'unit') {
        return
      }
      if (!checkboxKey.value.includes(c.Id)) {
        checkboxKey.value.push(c.Id)
        isSet = true
        autoChiose(c)
      }
    })
    return isSet
  }
  return false
}
const checkChange = (data, checked, indeterminate) => {
  const index = checkboxKey.value.findIndex((c) => c === data.Id)
  if (checked) {
    if (index !== -1) {
      return
    }
    checkboxKey.value.push(data.Id)
    if (autoChiose(data)) {
      deptTree.value.setCheckedKeys(checkboxKey.value, false)
    }
  } else if (index === -1) {
    return
  } else {
    checkboxKey.value.splice(index, 1)
  }
  const e = {
    isMultiple: props.isMultiple,
    comName: comNameCache,
    keys: [],
    value: []
  }
  checkboxKey.value.forEach((c) => {
    const item = deptDic[c]
    if (item != null) {
      e.value.push(item)
      e.keys.push(c)
    }
  })
  emit('update:modelValue', e.keys)
  emit('change', e.keys, e)
}
const chioseUnit = (dept) => {
  if (dept.disabled) {
    return
  }
  chioseKey.value = dept.Id
  const e = {
    isMultiple: props.isMultiple,
    companyId: dept.CompanyId,
    comName: comNameCache,
    keys: [],
    value: []
  }
  if (dept.type !== 'com') {
    e.value.push(deptDic[dept.Id])
    e.keys.push(dept.Id)
  }
  emit('update:modelValue', chioseKey.value)
  emit('change', e.keys, e)
}
watch(
  () => props.companyId,
  (comId: string) => {
    loadTree()
  },
  {
    immediate: true
  }
)
watch(
  () => props.unitId,
  (vals) => {
    if (vals != null && vals.length > 0) {
      loadTree()
    }
  },
  {
    immediate: false
  }
)
watch(
  () => props.isSubCompany,
  (vals) => {
    loadTree()
  }
)
watch(
  () => props.modelValue,
  (val) => {
    if (props.isMultiple) {
      checkboxKey.value = val ?? []
    } else {
      chioseKey.value = val
    }
  },
  {
    immediate: true
  }
)
defineExpose({
  refresh
})
</script>
